using System;
using System.Collections;
using System.Collections.Generic;

namespace CSharpBasicsExamples.ValueReferenceTypes
{
    // 值类型与引用类型示例
    
    // 值类型示例：结构体
    public struct Point
    {
        public int X { get; set; }
        public int Y { get; set; }
        
        public Point(int x, int y)
        {
            X = x;
            Y = y;
        }
        
        public double DistanceFromOrigin()
        {
            return Math.Sqrt(X * X + Y * Y);
        }
        
        public override string ToString()
        {
            return $"Point({X}, {Y})";
        }
        
        // 值类型的相等比较
        public override bool Equals(object obj)
        {
            if (obj is Point other)
            {
                return X == other.X && Y == other.Y;
            }
            return false;
        }
        
        public override int GetHashCode()
        {
            return HashCode.Combine(X, Y);
        }
    }
    
    // 引用类型示例：类
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Point Location { get; set; } // 包含值类型
        
        public Person(string name, int age)
        {
            Name = name;
            Age = age;
            Location = new Point(0, 0);
        }
        
        public void MoveTo(Point newLocation)
        {
            Location = newLocation;
        }
        
        public override string ToString()
        {
            return $"Person(Name={Name}, Age={Age}, Location={Location})";
        }
    }
    
    // 可空值类型示例
    public struct Temperature
    {
        public double Celsius { get; }
        
        public Temperature(double celsius)
        {
            Celsius = celsius;
        }
        
        public double Fahrenheit => Celsius * 9.0 / 5.0 + 32;
        
        public override string ToString()
        {
            return $"{Celsius:F1}°C ({Fahrenheit:F1}°F)";
        }
    }
    
    // 装箱拆箱演示类
    public class BoxingUnboxingDemo
    {
        public static void DemonstrateBoxingUnboxing()
        {
            Console.WriteLine("=== 装箱拆箱演示 ===\n");
            
            // 1. 装箱示例
            Console.WriteLine("1. 装箱 (Boxing):");
            int value = 42;
            object boxed = value;  // 装箱：int -> object
            Console.WriteLine($"原始值: {value} (类型: {value.GetType()})");
            Console.WriteLine($"装箱后: {boxed} (类型: {boxed.GetType()})");
            Console.WriteLine($"引用相等: {ReferenceEquals(value, boxed)}"); // false
            Console.WriteLine();
            
            // 2. 拆箱示例
            Console.WriteLine("2. 拆箱 (Unboxing):");
            object boxedValue = 100;
            int unboxed = (int)boxedValue;  // 拆箱：object -> int
            Console.WriteLine($"装箱的值: {boxedValue} (类型: {boxedValue.GetType()})");
            Console.WriteLine($"拆箱后: {unboxed} (类型: {unboxed.GetType()})");
            Console.WriteLine();
            
            // 3. 错误的拆箱
            Console.WriteLine("3. 错误的拆箱:");
            try
            {
                object stringValue = "Hello";
                int wrongUnbox = (int)stringValue;  // 这会抛出异常
            }
            catch (InvalidCastException ex)
            {
                Console.WriteLine($"拆箱异常: {ex.Message}");
            }
            Console.WriteLine();
            
            // 4. 性能对比
            Console.WriteLine("4. 性能对比:");
            PerformanceComparison();
        }
        
        private static void PerformanceComparison()
        {
            const int iterations = 1000000;
            
            // 使用 ArrayList (会发生装箱)
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();
            ArrayList arrayList = new ArrayList();
            for (int i = 0; i < iterations; i++)
            {
                arrayList.Add(i);  // 装箱
            }
            stopwatch.Stop();
            Console.WriteLine($"ArrayList (装箱): {stopwatch.ElapsedMilliseconds} ms");
            
            // 使用 List<int> (无装箱)
            stopwatch.Restart();
            List<int> list = new List<int>();
            for (int i = 0; i < iterations; i++)
            {
                list.Add(i);  // 无装箱
            }
            stopwatch.Stop();
            Console.WriteLine($"List<int> (无装箱): {stopwatch.ElapsedMilliseconds} ms");
            Console.WriteLine();
        }
    }
    
    // 值类型与引用类型行为对比
    public class ValueReferenceComparison
    {
        public static void DemonstrateValueTypes()
        {
            Console.WriteLine("=== 值类型行为演示 ===\n");
            
            // 值类型赋值 - 复制值
            Point p1 = new Point(10, 20);
            Point p2 = p1;  // 复制整个结构体
            
            Console.WriteLine($"原始点: {p1}");
            Console.WriteLine($"复制点: {p2}");
            
            // 修改 p2 不影响 p1
            p2.X = 100;
            Console.WriteLine($"修改 p2.X 后:");
            Console.WriteLine($"p1: {p1}");  // 不变
            Console.WriteLine($"p2: {p2}");  // 改变
            Console.WriteLine();
            
            // 值类型的默认值
            Point defaultPoint = default(Point);
            Console.WriteLine($"默认 Point: {defaultPoint}");
            
            // 可空值类型
            Point? nullablePoint = null;
            Console.WriteLine($"可空 Point: {nullablePoint}");
            Console.WriteLine($"HasValue: {nullablePoint.HasValue}");
            
            nullablePoint = new Point(5, 5);
            Console.WriteLine($"赋值后: {nullablePoint}");
            Console.WriteLine($"HasValue: {nullablePoint.HasValue}");
            Console.WriteLine($"Value: {nullablePoint.Value}");
            Console.WriteLine();
        }
        
        public static void DemonstrateReferenceTypes()
        {
            Console.WriteLine("=== 引用类型行为演示 ===\n");
            
            // 引用类型赋值 - 复制引用
            Person person1 = new Person("张三", 25);
            Person person2 = person1;  // 复制引用，指向同一对象
            
            Console.WriteLine($"原始人员: {person1}");
            Console.WriteLine($"引用人员: {person2}");
            Console.WriteLine($"引用相等: {ReferenceEquals(person1, person2)}"); // true
            
            // 修改 person2 会影响 person1（因为指向同一对象）
            person2.Name = "李四";
            person2.Age = 30;
            
            Console.WriteLine($"修改 person2 后:");
            Console.WriteLine($"person1: {person1}");  // 也被修改了
            Console.WriteLine($"person2: {person2}");
            Console.WriteLine();
            
            // 引用类型的默认值
            Person defaultPerson = default(Person);
            Console.WriteLine($"默认 Person: {defaultPerson}"); // null
            
            // null 检查
            if (defaultPerson == null)
            {
                Console.WriteLine("defaultPerson 是 null");
            }
            Console.WriteLine();
        }
        
        public static void DemonstrateMethodParameters()
        {
            Console.WriteLine("=== 方法参数传递演示 ===\n");
            
            // 值类型参数传递
            int number = 10;
            Console.WriteLine($"调用前 number: {number}");
            ModifyValueType(number);
            Console.WriteLine($"调用后 number: {number}"); // 不变
            
            // 值类型 ref 参数传递
            Console.WriteLine($"调用 ref 前 number: {number}");
            ModifyValueTypeByRef(ref number);
            Console.WriteLine($"调用 ref 后 number: {number}"); // 改变
            Console.WriteLine();
            
            // 引用类型参数传递
            Person person = new Person("王五", 35);
            Console.WriteLine($"调用前 person: {person}");
            ModifyReferenceType(person);
            Console.WriteLine($"调用后 person: {person}"); // 对象内容改变
            
            // 引用类型 ref 参数传递
            Person anotherPerson = new Person("赵六", 40);
            Console.WriteLine($"调用 ref 前 person: {anotherPerson}");
            ModifyReferenceTypeByRef(ref anotherPerson);
            Console.WriteLine($"调用 ref 后 person: {anotherPerson}"); // 引用改变
            Console.WriteLine();
        }
        
        private static void ModifyValueType(int value)
        {
            value = 999;
            Console.WriteLine($"方法内 value: {value}");
        }
        
        private static void ModifyValueTypeByRef(ref int value)
        {
            value = 888;
            Console.WriteLine($"方法内 ref value: {value}");
        }
        
        private static void ModifyReferenceType(Person person)
        {
            person.Name = "方法内修改";
            person.Age = 99;
            Console.WriteLine($"方法内 person: {person}");
        }
        
        private static void ModifyReferenceTypeByRef(ref Person person)
        {
            person = new Person("全新对象", 100);
            Console.WriteLine($"方法内 ref person: {person}");
        }
    }
    
    // 内存分配演示
    public class MemoryAllocationDemo
    {
        public static void DemonstrateMemoryAllocation()
        {
            Console.WriteLine("=== 内存分配演示 ===\n");
            
            // 栈上的值类型
            Console.WriteLine("1. 栈上的值类型:");
            int stackInt = 42;
            Point stackPoint = new Point(10, 20);
            Console.WriteLine($"栈上整数: {stackInt}");
            Console.WriteLine($"栈上结构体: {stackPoint}");
            Console.WriteLine();
            
            // 堆上的引用类型
            Console.WriteLine("2. 堆上的引用类型:");
            Person heapPerson = new Person("堆上的人", 25);
            string heapString = "堆上的字符串";
            Console.WriteLine($"堆上对象: {heapPerson}");
            Console.WriteLine($"堆上字符串: {heapString}");
            Console.WriteLine();
            
            // 值类型数组（在堆上，但元素是值类型）
            Console.WriteLine("3. 值类型数组:");
            int[] intArray = new int[] { 1, 2, 3, 4, 5 };
            Point[] pointArray = new Point[] 
            { 
                new Point(1, 1), 
                new Point(2, 2), 
                new Point(3, 3) 
            };
            
            Console.WriteLine($"整数数组: [{string.Join(", ", intArray)}]");
            Console.WriteLine($"点数组: [{string.Join(", ", pointArray)}]");
            Console.WriteLine();
            
            // 引用类型数组
            Console.WriteLine("4. 引用类型数组:");
            Person[] personArray = new Person[]
            {
                new Person("人员1", 20),
                new Person("人员2", 30),
                new Person("人员3", 40)
            };
            
            foreach (var p in personArray)
            {
                Console.WriteLine($"  {p}");
            }
        }
    }
    
    // 主演示程序
    public class ValueReferenceTypesDemo
    {
        public static void RunDemo()
        {
            Console.WriteLine("=== C# 值类型与引用类型演示 ===\n");
            
            // 1. 装箱拆箱演示
            BoxingUnboxingDemo.DemonstrateBoxingUnboxing();
            
            // 2. 值类型行为演示
            ValueReferenceComparison.DemonstrateValueTypes();
            
            // 3. 引用类型行为演示
            ValueReferenceComparison.DemonstrateReferenceTypes();
            
            // 4. 方法参数传递演示
            ValueReferenceComparison.DemonstrateMethodParameters();
            
            // 5. 内存分配演示
            MemoryAllocationDemo.DemonstrateMemoryAllocation();
            
            Console.WriteLine("\n=== 总结 ===");
            Console.WriteLine("值类型特点:");
            Console.WriteLine("- 直接存储数据值");
            Console.WriteLine("- 赋值时复制整个值");
            Console.WriteLine("- 通常分配在栈上");
            Console.WriteLine("- 有明确的默认值");
            Console.WriteLine("- 不能为 null（除非可空类型）");
            
            Console.WriteLine("\n引用类型特点:");
            Console.WriteLine("- 存储对象的引用（地址）");
            Console.WriteLine("- 赋值时复制引用");
            Console.WriteLine("- 对象分配在堆上");
            Console.WriteLine("- 默认值为 null");
            Console.WriteLine("- 可以为 null");
            
            Console.WriteLine("\n装箱拆箱:");
            Console.WriteLine("- 装箱：值类型 -> 引用类型（object）");
            Console.WriteLine("- 拆箱：引用类型（object）-> 值类型");
            Console.WriteLine("- 有性能开销，应尽量避免");
            Console.WriteLine("- 使用泛型可以避免装箱拆箱");
        }
    }
}
